package com.scheduledtest.demo.impl;

import com.scheduledtest.demo.ScheduledTaskJob;
import com.scheduledtest.demo.ScheduledTaskService;
import com.scheduledtest.demo.model.CostBaseScheduledConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {

    private ReentrantLock lock = new ReentrantLock();

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Autowired
    private ApplicationContext applicationContext;

    private Map<String, ScheduledFuture> scheduledFutureMap = new ConcurrentHashMap<>();

    @Override
    public Boolean start(String taskKey, CostBaseScheduledConfig scheduled) {
        log.info(">>>>>>启动任务{}<<<<<<<", taskKey);
        lock.lock();
        log.info(">>>>>加锁任务{}<<<<<<", taskKey);
        try {
            if (this.isStart(taskKey)) {
                log.info(">>>>当前任务已经启动 {}", taskKey);
                return false;
            }
            if (scheduled == null) {
                log.error("!!!!启动出错 {}", taskKey);
            }
            this.doStartTask(scheduled);
        } finally {
            lock.unlock();
            log.info(">>>释放锁<<<<");
        }
        log.info(">>>启动任务end {}<<<", taskKey);
        return null;
    }

    @Override
    public Boolean stop(String taskKey) {
        log.info(">>>>>>start停止任务{}<<<<<<<", taskKey);
        boolean taskFlag = scheduledFutureMap.containsKey(taskKey);
        if (taskFlag) {
            ScheduledFuture scheduledFuture = scheduledFutureMap.get(taskKey);
            boolean cancel = scheduledFuture.cancel(true);
            log.info(">>>cancel 任务 {}<<<", taskKey);
            scheduledFutureMap.remove(taskKey);
        }

        log.info(">>>启动任务end {}<<<", taskKey);
        return null;
    }

    @Override
    public Boolean restart(String taskKey, CostBaseScheduledConfig scheduled) {
        log.info(">>>>>>重启任务{}<<<<<<<", taskKey);
        this.stop(taskKey);
        if (scheduled == null) {
            //通过taskKey查询数据库 得到配置
        }
        if (scheduled == null) {
            return false;
        }
        return this.start(taskKey, scheduled);
    }

    @Override
    public void initAllTask() {
        List<CostBaseScheduledConfig> costBaseScheduledConfigs = new ArrayList<>();
        CostBaseScheduledConfig costBaseScheduledConfig = new CostBaseScheduledConfig();
        costBaseScheduledConfig.setId("11");
        costBaseScheduledConfig.setScheduledCode("ScheduledTaskJobImpl");
        costBaseScheduledConfig.setScheduledName("编码1");
        costBaseScheduledConfig.setCronStr("0 0/1 * * * ?");
        costBaseScheduledConfigs.add(costBaseScheduledConfig);
        log.info(">>>初始化 定时器 size={}", costBaseScheduledConfigs == null ? 0 : costBaseScheduledConfigs.size());
        if (costBaseScheduledConfigs == null || costBaseScheduledConfigs.size() < 1) {
            return;
        }
        for (CostBaseScheduledConfig i : costBaseScheduledConfigs) {
            String scheduledCode = i.getScheduledCode();
            if (this.isStart(scheduledCode)) {
                this.restart(scheduledCode, i);
            } else {
                this.doStartTask(i);
            }
        }

    }

    private void doStartTask(CostBaseScheduledConfig i) {
        if (i == null) {
            return;
        }
        String scheduledCode = i.getScheduledCode();
        String scheduledName = i.getScheduledName();
        String cronStr = i.getCronStr();
        ScheduledTaskJob bean = (ScheduledTaskJob) applicationContext.getBean(scheduledCode);
        log.info(">>>>任务{} 规则{}", scheduledName, cronStr);
        ScheduledFuture<?> schedule = threadPoolTaskScheduler
                .schedule(bean,
                        (TriggerContext triggerContext) -> new CronTrigger(cronStr).nextExecutionTime(triggerContext));
        scheduledFutureMap.put(scheduledCode, schedule);
    }

    private boolean isStart(String taskKey) {
        if (scheduledFutureMap.containsKey(taskKey)) {
            if (!scheduledFutureMap.get(taskKey).isCancelled()) {
                return true;
            }
        }
        return false;
    }
}
